define("dojox/widget/Roller", ["dojo", "dijit", "dijit/_Widget"], function (dojo, dijit) {

    dojo.declare("dojox.widget.Roller", dijit._Widget, {
        // summary:
        //		A simple widget to take an unordered-list of Text and roll through them
        // description:
        //		The Roller widget takes an unordered-list of items, and converts
        //		them to a single-area (the size of one list-item, however you so choose
        //		to style it) and loops continually, fading between items.
        //
        //		In it's current state, it requires it be created from an unordered (or ordered)
        //		list, though can contain complex markup.
        //
        //		You can manipulate the `items` array at any point during the cycle with
        //		standard array manipulation techniques.
        //
        //		The class "dojoxRoller" is added to the UL element for styling purposes.
        // example:
        //	|	// create a scroller from a unordered list with id="lister"
        //	|	var thinger = new dojox.widget.Roller.Roller({},"lister");
        //
        // example:
        //	|	// create a scroller from a fixed array, and place in the DOM:
        //	|	new dojox.widget.Roller({ items:["one","two","three"] }).placeAt(dojo.body());
        //
        // example:
        //	|	// add an item:
        //	|	dijit.byId("roller").items.push("I am a new Label");
        //
        // example:
        //	|	// stop a roller from rolling:
        //	|	dijit.byId("roller").stop();

        // delay: Integer
        //		Interval between rolls
        delay:2000,

        // autoStart: Boolean
        //		Toggle to control starup behavior. Call .start() manually
        //		if set to `false`
        autoStart:true,

        // itemSelector: String
        //		A CSS selector to be used by `dojo.query` to find the children
        //		items in this widget. Defaults to "> li", finding only first-children
        //		list-items in the list, allowing for embedded lists to occur.
        itemSelector:"> li",

        // durationIn: Integer
        //		Speed (in ms) to apply to the "in" animation (show the node)
        durationIn:400,

        // durationOut: Integer
        //		Speed (in ms) to apply to the "out" animation (hide the showing node)
        durationOut:275,
        /*=====
         // items: Array
         //		If populated prior to instantiation, is used as the Items over the children
         items: [],
         =====*/

        // _idx: Integer
        //		Index of the the currently visible item in the list of items[]
        _idx:-1,

        postCreate:function () {

            // add some instance vars:
            if (!this["items"]) {
                this.items = [];
            }

            dojo.addClass(this.domNode, "dojoxRoller");

            // find all the items in this list, and popuplate
            dojo.query(this.itemSelector, this.domNode).forEach(function (item, i) {
                this.items.push(item.innerHTML);
                // reuse the first match, destroy the rest
                if (i == 0) {
                    this._roller = item;
                    this._idx = 0;
                } else {
                    dojo.destroy(item);
                }
            }, this);

            // handle the case where items[] were passed, and no srcNodeRef exists
            if (!this._roller) {
                this._roller = dojo.create('li', null, this.domNode);
            }
            // stub out animation creation (for overloading maybe later)
            this.makeAnims();

            // and start, if true:
            if (this.autoStart) {
                this.start();
            }

        },

        makeAnims:function () {
            // summary:
            //		Animation creator function. Need to create an 'in' and 'out'
            //		Animation stored in _anim Object, which the rest of the widget
            //		will reuse.
            var n = this.domNode;
            dojo.mixin(this, {
                _anim:{
                    "in":dojo.fadeIn({ node:n, duration:this.durationIn }),
                    "out":dojo.fadeOut({ node:n, duration:this.durationOut })
                }
            });
            this._setupConnects();

        },

        _setupConnects:function () {
            // summary:
            //		setup the loop connection logic
            var anim = this._anim;

            this.connect(anim["out"], "onEnd", function () {
                // onEnd of the `out` animation, select the next items and play `in` animation
                this._setIndex(this._idx + 1);
                anim["in"].play(15);
            });

            this.connect(anim["in"], "onEnd", function () {
                // onEnd of the `in` animation, call `start` again after some delay:
                this._timeout = setTimeout(dojo.hitch(this, "_run"), this.delay);
            });
        },

        start:function () {
            // summary:
            //		Starts to Roller looping
            if (!this.rolling) {
                this.rolling = true;
                this._run();
            }
        },

        _run:function () {
            this._anim["out"].gotoPercent(0, true);
        },

        stop:function () {
            // summary:
            //		Stops the Roller from looping anymore.
            this.rolling = false;

            var m = this._anim,
                t = this._timeout;

            if (t) {
                clearTimeout(t);
            }
            m["in"].stop();
            m["out"].stop();
        },

        _setIndex:function (i) {
            // summary:
            //		Set the Roller to some passed index. If beyond range, go to first.
            var l = this.items.length - 1;
            if (i < 0) {
                i = l;
            }
            if (i > l) {
                i = 0;
            }
            this._roller.innerHTML = this.items[i] || "error!";
            this._idx = i;
        }

    });

    dojo.declare("dojox.widget.RollerSlide", dojox.widget.Roller, {
        // summary:
        //		An add-on to the Roller to modify animations. This produces
        //		a slide-from-bottom like effect. See `dojox.widget.Roller` for
        //		full API information.

        durationOut:175, // slightly faster than default

        makeAnims:function () {
            // summary:
            //		Animation creator function. Need to create an 'in' and 'out'
            //		Animation stored in _anim Object, which the rest of the widget
            //		will reuse.

            var n = this.domNode, pos = "position",
                props = {
                    top:{ end:0, start:25 },
                    opacity:1
                }
                ;

            dojo.style(n, pos, "relative");
            dojo.style(this._roller, pos, "absolute");

            dojo.mixin(this, {
                _anim:{

                    "in":dojo.animateProperty({
                        node:n,
                        duration:this.durationIn,
                        properties:props
                    }),

                    "out":dojo.fadeOut({ node:n, duration:this.durationOut })
                }
            });
            // don't forget to do this in the class. override if necessary.
            this._setupConnects();
        }

    });

    dojo.declare("dojox.widget._RollerHover", null, {
        // summary:
        //		A mixin class to provide a way to automate the "stop on hover" functionality.
        //
        // description:
        //		A mixin class used to provide a way to automate a "stop on hover" behavior,
        //		while still allowing for ambigious subclassing for custom animations.
        //		Simply mix this class into a `dojox.widget.Roller` variant, and instantiate
        //		as you would. The hover connection is done automatically.
        //
        //		The "hover" functionality is as such: Stop rotation while the mouse is over the
        //		instance, and resume again once leaving. Even if autoStart is disabled, the widget
        //		will start if a mouse enters and leaves the node in this case.
        //
        // example:
        // |	dojo.declare("my.Roller", [dojox.widget.RollerSlide, dojox.widget._RollerHover], {});
        // |	new my.Roller({}, "myList");

        postCreate:function () {
            this.inherited(arguments);
            this.connect(this.domNode, "onmouseenter", "stop");
            this.connect(this.domNode, "onmouseleave", "start");
        }

    });

    return dojox.widget.Roller;

});
